package server;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import dpssinterface.dpssInterface;
import com.google.common.collect.ArrayListMultimap;

public class GameServer extends UnicastRemoteObject implements dpssInterface {
	int currentServerPortNo=0;
	String currentServer=null;
	static int count1=0,count2=0,count3=0,count4=0,count5=0,count6=0;
	 static int x=0;
	private static final long serialVersionUID = 1L;
	
    public ArrayListMultimap<String,Object> myMultimap = ArrayListMultimap.create();
    public ConcurrentHashMap<String,String> onlineentry = new ConcurrentHashMap<String,String>();
	
        
    protected GameServer(int portnumber) throws RemoteException
	{
		super();
		currentServerPortNo=portnumber;
	}

	public String createPlayerAccount(String FirstName, String LastName, int Age, String Username,String Password, String IPAddress) throws RemoteException
	{	
   	 if (IPAddress.startsWith("132")){count1 = count1 +1 ;}
   	 else if (IPAddress.startsWith("93")){count2 = count2 +1 ;}
	 else {count3 = count3 +1 ;}
		
		String message = "";
		final Object lock = new Object();
	try{
			synchronized(lock){
		if (!myMultimap.containsKey(Username)){
					myMultimap.put(Username, FirstName);
					myMultimap.put(Username, LastName);
					myMultimap.put(Username, Age);
					myMultimap.put(Username, Username);
					myMultimap.put(Username, Password);
			        myMultimap.put(Username, IPAddress);
			       
			      
			   } else {

				   return message + "Username already exists!" ; }
		
			}
	}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		 this.logfile(Username,"Created Account at");
		return message + "Successfully created" ;

		
	}

     public  String playerSignIn(String Username, String Password,String IPAddress)throws RemoteException{
           
    	     	 String message = "";
            if (myMultimap.containsKey(Username)){
            	if(myMultimap.containsValue(Password)){
            		if(onlineentry.get(Username) == null){
            			if (IPAddress.startsWith("132")){
            		onlineentry.put(Username,IPAddress);}
            			else if (IPAddress.startsWith("93")){
                    		onlineentry.put(Username,IPAddress);}
            			else {
                    		onlineentry.put(Username,IPAddress);}
            		if (IPAddress.startsWith("132")){count4 = count4 +1 ;}
               	 else if (IPAddress.startsWith("93")){count5 = count5 +1 ;}
               	 else {count6 = count6 +1 ;}

            		this.logfile(Username,"Signed in at");
            		
            		return message + "You are signed in";
            		
            		}
            		else { return message + "you are already signed in"; }
            		}else {
            			this.logfile(Username,"Unauthorized access at");
            			return message + "password is wrong";}
            }else{
            	this.logfile(Username,"Unauthorized access at");
            	return message + "username is wrong";}
           
    		
        }
    
      public  String playerSignOut(String Username,String IPAddress)throws RemoteException{
            String message = "" ;
            
            if(onlineentry.get(Username)!=null){
            	
            		 String x = onlineentry.get(Username);
            		 if(x.equals(IPAddress)){
            			 onlineentry.remove(Username);
            			 count4 = count4 - 1 ;
                         this.logfile(Username,"Signed out at");
                         message = message + "Successfully Signed out from the list" ;
            		}else{
            			this.logfile(Username,"Unsuccessful Signed Out at");
                        message = message + "Username is signed in from another server, please enter correct IP address." ;
            			
            		}
            	
               
            }else{
            	this.logfile(Username,"Unsuccessful Signed Out at");
                message = message + "Player is offline" ;
               }
            return message;
        }
	
      public synchronized int getlocalCountonline()
  	{
  		int noOfRecords = 0;
  		noOfRecords =onlineentry.size() ;
  		return noOfRecords ;
  	}

      public synchronized int getlocalCountoffline()
    	{
    	 
    	  	if (currentServerPortNo == 5789){
    	  		 x =count1 - count4;
    	  		}
    		if (currentServerPortNo == 5799){
   	  		 x =count2 - count5;
   	  		}
    		if (currentServerPortNo == 6000){
   	  		 x =count3 - count6;
   	  		}
    	return x;
    	}

      
      public void getPlayerStatus(String Username, String Password, String IPAddress) throws RemoteException
	{
		String Server1 = null,Server2 = null;
		int ServerPort1=0,ServerPort2=0;
		if (IPAddress.startsWith("132"))
			{
				currentServer="North";
				Server1 = "Europe";
				Server2 = "Asia";
				ServerPort1 = 5799;
				ServerPort2 = 6000;
				this.logfile(Username," accessed from NorthAmerica at");
			}
		else if (IPAddress.startsWith("93"))
		{
			currentServer = "Europe";
			Server1 = "North";
			Server2 = "Asia";
			ServerPort1 = 5789;
			ServerPort2 = 6000;
			this.logfile(Username," accessed from Europe at");
		}
		else
		{
			currentServer = "Asia";
			Server1 = "North";
			Server2 = "Europe";
			ServerPort1 = 5789;
			ServerPort2 = 5799;
			this.logfile(Username," accessed from Asia at");
			}
		int gn;
		int noOfRecords;
		gn = getlocalCountoffline();
		noOfRecords = getlocalCountonline();
		System.out.println(" ");
		System.out.println(currentServer+":"+" "+noOfRecords+" "+"Online" + ", "+gn+" "+"Offline");
		sendUDP_request(Server1, ServerPort1, Server2, ServerPort2);
    	}
		
	private void sendUDP_request(String Server1 , int ServerPort1, String Server2, int ServerPort2)
	{
		int [] portNumbers = new int[]{ServerPort1,ServerPort2};
		for(int i =0; i<2;i++)
		{
			DatagramSocket clientSocket = null;
			try{
				clientSocket = new DatagramSocket();
				byte [] serverInfo = (Server1+ServerPort1).getBytes();
				InetAddress IP = InetAddress.getByName("localhost");
				DatagramPacket request = new DatagramPacket(serverInfo, serverInfo.length,IP,portNumbers[i]);
				clientSocket.send(request);
				byte [] ServerCount = new byte[1024];
				DatagramPacket reply = new DatagramPacket(ServerCount,ServerCount.length);
				clientSocket.receive(reply);
				System.out.println(new String(reply.getData()).trim());
				
			}catch(SocketException e){System.out.println("Socket:" +e.getMessage());
			}catch(IOException e){ System.out.println("IO: "+e.getMessage());
			}finally {if(clientSocket != null)clientSocket.close(); }
		}
	}
	
	public static void main(String[] args) {
		
		try{
			GameServer   NorthServer = new GameServer(5789);
			GameServer   EuropeServer = new GameServer(5799);
			GameServer   AsiaServer = new GameServer(6000);
			LocateRegistry.createRegistry(1099);
            Registry registry = LocateRegistry.getRegistry();
                       
			registry.rebind("North",NorthServer);
			registry.rebind("Europe",EuropeServer);
			registry.rebind("Asia",AsiaServer);
			System.out.println(" RMI connections ready");
			
		 	(new dpssUDP("North",5789,NorthServer)).start();
			(new dpssUDP("Europe",5799,EuropeServer)).start();
			(new dpssUDP("Asia",6000,AsiaServer)).start();
			}
		catch(Exception ex){
			ex.printStackTrace();
		}
	}
	
	@SuppressWarnings("deprecation")
	public int getTiming(String Timing){
		
		Date logTime = new Date();
		int result ;
		
		if(Timing.equals("Hour")){
			result = logTime.getHours();
			
		}else if(Timing.equals("Minute")){
			result = logTime.getMinutes();
		}else{
			result = logTime.getSeconds();
		}
		return result ;
	}
	
	public void logfile(String Username,String info){
	    	File file;
	    	BufferedWriter bufferedwritter = null;
	    	try{
	    		file = new File(Username+".txt");
	    		if(!file.isFile()){
	    			file.createNewFile();
	    		}	
                        FileWriter fileWriter = new FileWriter(file.getName(),true);
		        bufferedwritter = new BufferedWriter(fileWriter);

		        bufferedwritter.newLine();
		        String  message  =  "Username:" + Username +  info;  
		        
		        int Hour = getTiming("Hour");
		        int Minute = getTiming("Minute");
		        int Second = getTiming("Seconds");
		     
		        message = message +"  " + "Hours" + Hour +"  "+ "Minutes" + Minute +"  "+ "Seconds" +"  " + Second; 
                        bufferedwritter.write(message);
	    	}

	    	catch(IOException ioe){
	    		System.out.println("IO Exceptions " +ioe);
	    			    	}
			catch(Exception e){
				System.out.println(" Un Known Exceptions " +e);
				}
			finally{
				try {
					if(bufferedwritter!=null){
						bufferedwritter.close();
					}
				}
				catch (IOException e) {

					e.printStackTrace();
				}
			}	
	    } 
}
